home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 26 / Cream of the Crop 26.iso / program / nasm095s.zip / NASM.C < prev    next >
C/C++ Source or Header  |  1997-07-27  |  26KB  |  963 lines

  1. /* The Netwide Assembler main program module
  2.  *
  3.  * The Netwide Assembler is copyright (C) 1996 Simon Tatham and
  4.  * Julian Hall. All rights reserved. The software is
  5.  * redistributable under the licence given in the file "Licence"
  6.  * distributed in the NASM archive.
  7.  */
  8.  
  9. #include <stdio.h>
  10. #include <stdarg.h>
  11. #include <stdlib.h>
  12. #include <string.h>
  13. #include <ctype.h>
  14.  
  15. #include "nasm.h"
  16. #include "nasmlib.h"
  17. #include "preproc.h"
  18. #include "parser.h"
  19. #include "assemble.h"
  20. #include "labels.h"
  21. #include "outform.h"
  22. #include "listing.h"
  23.  
  24. static void report_error (int, char *, ...);
  25. static void parse_cmdline (int, char **);
  26. static void assemble_file (char *);
  27. static int getkw (char *buf, char **value);
  28. static void register_output_formats(void);
  29. static void usage(void);
  30.  
  31. static char *obuf;
  32. static char inname[FILENAME_MAX];
  33. static char outname[FILENAME_MAX];
  34. static char listname[FILENAME_MAX];
  35. static char realout[FILENAME_MAX];
  36. static int lineno;               /* for error reporting */
  37. static int lineinc;               /* set by [LINE] or [ONELINE] */
  38. static int globallineno;           /* for forward-reference tracking */
  39. static int pass;
  40. static struct ofmt *ofmt = NULL;
  41.  
  42. static FILE *ofile = NULL;
  43. static int sb = 16;               /* by default */
  44.  
  45. static int use_stdout = FALSE;           /* by default, errors to stderr */
  46.  
  47. static long current_seg;
  48. static struct RAA *offsets;
  49. static long abs_offset;
  50.  
  51. static struct SAA *forwrefs;           /* keep track of forward references */
  52. static int forwline;
  53.  
  54. static Preproc *preproc;
  55. static int preprocess_only;
  56.  
  57. /* used by error function to report location */
  58. static char currentfile[FILENAME_MAX];
  59.  
  60. /*
  61.  * Which of the suppressible warnings are suppressed. Entry zero
  62.  * doesn't do anything. Initial defaults are given here.
  63.  */
  64. static char suppressed[1+ERR_WARN_MAX] = {
  65.     0, FALSE, TRUE
  66. };
  67.  
  68. /*
  69.  * The option names for the suppressible warnings. As before, entry
  70.  * zero does nothing.
  71.  */
  72. static char *suppressed_names[1+ERR_WARN_MAX] = {
  73.     NULL, "macro-params", "orphan-labels"
  74. };
  75.  
  76. /*
  77.  * The explanations for the suppressible warnings. As before, entry
  78.  * zero does nothing.
  79.  */
  80. static char *suppressed_what[1+ERR_WARN_MAX] = {
  81.     NULL, "macro calls with wrong no. of params",
  82.     "labels alone on lines without trailing `:'"
  83. };
  84.  
  85. /*
  86.  * This is a null preprocessor which just copies lines from input
  87.  * to output. It's used when someone explicitly requests that NASM
  88.  * not preprocess their source file.
  89.  */
  90.  
  91. static void no_pp_reset (char *, efunc, ListGen *);
  92. static char *no_pp_getline (void);
  93. static void no_pp_cleanup (void);
  94. static Preproc no_pp = {
  95.     no_pp_reset,
  96.     no_pp_getline,
  97.     no_pp_cleanup
  98. };
  99.  
  100. /*
  101.  * get/set current offset...
  102.  */
  103. #define get_curr_ofs (current_seg==NO_SEG?abs_offset:\
  104.               raa_read(offsets,current_seg))
  105. #define set_curr_ofs(x) (current_seg==NO_SEG?(void)(abs_offset=(x)):\
  106.              (void)(offsets=raa_write(offsets,current_seg,(x))))
  107.  
  108. static int want_usage;
  109. static int terminate_after_phase;
  110.  
  111. int main(int argc, char **argv) {
  112.     want_usage = terminate_after_phase = FALSE;
  113.  
  114.     nasm_set_malloc_error (report_error);
  115.     offsets = raa_init();
  116.     forwrefs = saa_init ((long)sizeof(int));
  117.  
  118.     preproc = &nasmpp;
  119.     preprocess_only = FALSE;
  120.  
  121.     seg_init();
  122.  
  123.     register_output_formats();
  124.  
  125.     parse_cmdline(argc, argv);
  126.  
  127.     if (terminate_after_phase) {
  128.     if (want_usage)
  129.         usage();
  130.     return 1;
  131.     }
  132.  
  133.     if (preprocess_only) {
  134.     char *line;
  135.  
  136.     if (*outname) {
  137.         ofile = fopen(outname, "w");
  138.         if (!ofile)
  139.         report_error (ERR_FATAL | ERR_NOFILE,
  140.                   "unable to open output file `%s'", outname);
  141.     } else
  142.         ofile = NULL;
  143.     preproc->reset (inname, report_error, &nasmlist);
  144.     strcpy(currentfile,inname);
  145.     lineno = 0;
  146.     lineinc = 1;
  147.     while ( (line = preproc->getline()) ) {
  148.         lineno += lineinc;
  149.         if (ofile) {
  150.         fputs(line, ofile);
  151.         fputc('\n', ofile);
  152.         } else
  153.         puts(line);
  154.         nasm_free (line);
  155.     }
  156.     preproc->cleanup();
  157.     if (ofile)
  158.         fclose(ofile);
  159.     if (ofile && terminate_after_phase)
  160.         remove(outname);
  161.     } else {
  162.     /*
  163.      * We must call ofmt->filename _anyway_, even if the user
  164.      * has specified their own output file, because some
  165.      * formats (eg OBJ and COFF) use ofmt->filename to find out
  166.      * the name of the input file and then put that inside the
  167.      * file.
  168.      */
  169.     ofmt->filename (inname, realout, report_error);
  170.     if (!*outname) {
  171.         strcpy(outname, realout);
  172.     }
  173.  
  174.     ofile = fopen(outname, "wb");
  175.     if (!ofile) {
  176.         report_error (ERR_FATAL | ERR_NOFILE,
  177.               "unable to open output file `%s'", outname);
  178.     }
  179.     /*
  180.      * We must call init_labels() before ofmt->init() since
  181.      * some object formats will want to define labels in their
  182.      * init routines. (eg OS/2 defines the FLAT group)
  183.      */
  184.     init_labels ();
  185.     ofmt->init (ofile, report_error, define_label);
  186.     assemble_file (inname);
  187.     if (!terminate_after_phase) {
  188.         ofmt->cleanup ();
  189.         cleanup_labels ();
  190.     }
  191.     /*
  192.      * We had an fclose on the output file here, but we
  193.      * actually do that in all the object file drivers as well,
  194.      * so we're leaving out the one here.
  195.      *     fclose (ofile);
  196.      */
  197.     if (terminate_after_phase) {
  198.         remove(outname);
  199.         if (listname[0])
  200.         remove(listname);
  201.     }
  202.     }
  203.  
  204.     if (want_usage)
  205.     usage();
  206.     raa_free (offsets);
  207.     saa_free (forwrefs);
  208.  
  209.     if (terminate_after_phase)
  210.     return 1;
  211.     else
  212.     return 0;
  213. }
  214.  
  215. static int process_arg (char *p, char *q) {
  216.     char *param;
  217.     int i;
  218.     int advance = 0;
  219.  
  220.     if (!p || !p[0])
  221.     return 0;
  222.  
  223.     if (p[0]=='-') {
  224.     switch (p[1]) {
  225.       case 's':
  226.         use_stdout = TRUE;
  227.         break;
  228.       case 'o':               /* these parameters take values */
  229.       case 'f':
  230.       case 'p':
  231.       case 'd':
  232.       case 'i':
  233.       case 'l':
  234.         if (p[2])               /* the parameter's in the option */
  235.         param = p+2;
  236.         else if (!q) {
  237.         report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
  238.                   "option `-%c' requires an argument",
  239.                   p[1]);
  240.         break;
  241.         } else
  242.         advance = 1, param = q;
  243.         if (p[1]=='o') {           /* output file */
  244.         strcpy (outname, param);
  245.         } else if (p[1]=='f') {    /* output format */
  246.         ofmt = ofmt_find(param);
  247.         if (!ofmt) {
  248.             report_error (ERR_FATAL | ERR_NOFILE | ERR_USAGE,
  249.                   "unrecognised output format `%s'",
  250.                   param);
  251.         }
  252.         } else if (p[1]=='p') {    /* pre-include */
  253.         pp_pre_include (param);
  254.         } else if (p[1]=='d') {    /* pre-define */
  255.         pp_pre_define (param);
  256.         } else if (p[1]=='i') {    /* include search path */
  257.         pp_include_path (param);
  258.         } else if (p[1]=='l') {    /* listing file */
  259.         strcpy (listname, param);
  260.         }
  261.         break;
  262.       case 'h':
  263.         fprintf(use_stdout ? stdout : stderr,
  264.             "usage: nasm [-o outfile] [-f format] [-l listfile]"
  265.             " [options...] filename\n");
  266.         fprintf(use_stdout ? stdout : stderr,
  267.             "    or nasm -r   for version info\n\n");
  268.         fprintf(use_stdout ? stdout : stderr,
  269.             "    -e means preprocess only; "
  270.             "-a means don't preprocess\n");
  271.         fprintf(use_stdout ? stdout : stderr,
  272.             "    -s means send errors to stdout not stderr\n");
  273.         fprintf(use_stdout ? stdout : stderr,
  274.             "    -i<path> adds a pathname to the include file"
  275.             " path\n    -p<file> pre-includes a file;"
  276.             " -d<macro>[=<value] pre-defines a macro\n");
  277.         fprintf(use_stdout ? stdout : stderr,
  278.             "    -w+foo enables warnings about foo; "
  279.             "-w-foo disables them\n  where foo can be:\n");
  280.         for (i=1; i<=ERR_WARN_MAX; i++)
  281.         fprintf(use_stdout ? stdout : stderr,
  282.             "    %-16s%s (default %s)\n",
  283.             suppressed_names[i], suppressed_what[i],
  284.             suppressed[i] ? "off" : "on");
  285.         fprintf(use_stdout ? stdout : stderr,
  286.             "\nvalid output formats for -f are"
  287.             " (`*' denotes default):\n");
  288.         ofmt_list(ofmt, use_stdout ? stdout : stderr);
  289.         exit (0);               /* never need usage message here */
  290.         break;
  291.       case 'r':
  292.         fprintf(use_stdout ? stdout : stderr,
  293.             "NASM version %s\n", NASM_VER);
  294.         exit (0);               /* never need usage message here */
  295.         break;
  296.       case 'e':               /* preprocess only */
  297.         preprocess_only = TRUE;
  298.         break;
  299.       case 'a':               /* assemble only - don't preprocess */
  300.         preproc = &no_pp;
  301.         break;
  302.       case 'w':
  303.         if (p[2] != '+' && p[2] != '-') {
  304.         report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
  305.                   "invalid option to `-w'");
  306.         } else {
  307.         for (i=1; i<=ERR_WARN_MAX; i++)
  308.             if (!nasm_stricmp(p+3, suppressed_names[i]))
  309.             break;
  310.         if (i <= ERR_WARN_MAX)
  311.             suppressed[i] = (p[2] == '-');
  312.         else
  313.             report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
  314.                   "invalid option to `-w'");
  315.         }
  316.         break;
  317.       default:
  318.         report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
  319.               "unrecognised option `-%c'",
  320.               p[1]);
  321.         break;
  322.     }
  323.     } else {
  324.     if (*inname) {
  325.         report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
  326.               "more than one input file specified");
  327.     } else
  328.         strcpy(inname, p);
  329.     }
  330.  
  331.     return advance;
  332. }
  333.  
  334. static void parse_cmdline(int argc, char **argv) {
  335.     char *envreal, *envcopy, *p, *q, *arg, *prevarg;
  336.     char separator = ' ';
  337.  
  338.     *inname = *outname = *listname = '\0';
  339.  
  340.     /*
  341.      * First, process the NASM environment variable.
  342.      */
  343.     envreal = getenv("NASM");
  344.     arg = NULL;
  345.     if (envreal) {
  346.     envcopy = nasm_strdup(envreal);
  347.     p = envcopy;
  348.     if (*p && *p != '-')
  349.         separator = *p++;
  350.     while (*p) {
  351.         q = p;
  352.         while (*p && *p != separator) p++;
  353.         while (*p == separator) *p++ = '\0';
  354.         prevarg = arg;
  355.         arg = q;
  356.         if (process_arg (prevarg, arg))
  357.         arg = NULL;
  358.     }
  359.     nasm_free (envcopy);
  360.     }
  361.     if (arg)
  362.     process_arg (arg, NULL);
  363.  
  364.     /*
  365.      * Now process the actual command line.
  366.      */
  367.     while (--argc) {
  368.     int i;
  369.     argv++;
  370.     i = process_arg (argv[0], argc > 1 ? argv[1] : NULL);
  371.     argv += i, argc -= i;
  372.     }
  373.  
  374.     if (!*inname)
  375.     report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
  376.               "no input file specified");
  377. }
  378.  
  379. static void assemble_file (char *fname) {
  380.     char *value, *p, *line;
  381.     insn output_ins;
  382.     int i, rn_error;
  383.     long seg;
  384.  
  385.     /* pass one */
  386.     pass = 1;
  387.     current_seg = ofmt->section(NULL, pass, &sb);
  388.     preproc->reset(fname, report_error, &nasmlist);
  389.     strcpy(currentfile,fname);
  390.     lineno = 0;
  391.     lineinc = 1;
  392.     globallineno = 0;
  393.     while ( (line = preproc->getline()) ) {
  394.     lineno += lineinc;
  395.     globallineno++;
  396.  
  397.     if (line[0] == '%') {
  398.         int ln, li;
  399.         char buf[FILENAME_MAX];
  400.  
  401.         /*
  402.          * This will be a line number directive. They come
  403.          * straight from the preprocessor, so we'll subject
  404.          * them to only minimal error checking.
  405.          */
  406.         if (strncmp(line, "%line", 5)) {
  407.         if (preproc == &no_pp)
  408.             report_error (ERR_WARNING, "unknown `%%' directive in "
  409.                   " preprocessed source");
  410.         } else if (sscanf(line, "%%line %d+%d %s", &ln, &li, buf) != 3) {
  411.         report_error (ERR_WARNING, "bogus line number directive in"
  412.                   " preprocessed source");
  413.         } else {
  414.         lineno = ln - li;
  415.         lineinc = li;
  416.         strncpy (currentfile, buf, FILENAME_MAX-1);
  417.         currentfile[FILENAME_MAX-1] = '\0';
  418.         }
  419.         continue;
  420.     }
  421.  
  422.     /* here we parse our directives; this is not handled by the 'real'
  423.      * parser. */
  424.     if ( (i = getkw (line, &value)) ) {
  425.         switch (i) {
  426.           case 1:           /* [SEGMENT n] */
  427.         seg = ofmt->section (value, pass, &sb);
  428.         if (seg == NO_SEG) {
  429.             report_error (ERR_NONFATAL,
  430.                   "segment name `%s' not recognised",
  431.                   value);
  432.         } else {
  433.             current_seg = seg;
  434.         }
  435.         break;
  436.           case 2:           /* [EXTERN label] */
  437.         if (*value == '$')
  438.             value++;           /* skip initial $ if present */
  439.         declare_as_global (value, report_error);
  440.         define_label (value, seg_alloc(), 0L, ofmt, report_error);
  441.         break;
  442.           case 3:           /* [BITS bits] */
  443.         switch (atoi(value)) {
  444.           case 16:
  445.           case 32:
  446.             sb = atoi(value);
  447.             break;
  448.           default:
  449.             report_error(ERR_NONFATAL,
  450.                  "`%s' is not a valid argument to [BITS]",
  451.                  value);
  452.             break;
  453.         }
  454.         break;
  455.           case 4:           /* [GLOBAL symbol] */
  456.         if (*value == '$')
  457.             value++;           /* skip initial $ if present */
  458.         declare_as_global (value, report_error);
  459.         break;
  460.           case 5:           /* [COMMON symbol size] */
  461.         p = value;
  462.         while (*p && !isspace(*p))
  463.             p++;
  464.         if (*p) {
  465.             long size;
  466.  
  467.             while (*p && isspace(*p))
  468.             *p++ = '\0';
  469.             size = readnum (p, &rn_error);
  470.             if (rn_error)
  471.             report_error (ERR_NONFATAL, "invalid size specified"
  472.                       " in COMMON declaration");
  473.             else
  474.             define_common (value, seg_alloc(), size,
  475.                        ofmt, report_error);
  476.         } else
  477.             report_error (ERR_NONFATAL, "no size specified in"
  478.                   " COMMON declaration");
  479.         break;
  480.           case 6:               /* [ABSOLUTE address] */
  481.         current_seg = NO_SEG;
  482.         abs_offset = readnum(value, &rn_error);
  483.         if (rn_error) {
  484.             report_error (ERR_NONFATAL, "invalid address specified"
  485.                   " for ABSOLUTE directive");
  486.             abs_offset = 0x100;/* don't go near zero in case of / */
  487.         }
  488.         break;
  489.           default:
  490.         if (!ofmt->directive (line+1, value, 1))
  491.             report_error (ERR_NONFATAL, "unrecognised directive [%s]",
  492.                   line+1);
  493.         break;
  494.         }
  495.     } else {
  496.         long offs = get_curr_ofs;
  497.         parse_line (current_seg, offs, lookup_label,
  498.             1, line, &output_ins, ofmt, report_error);
  499.         if (output_ins.forw_ref)
  500.         *(int *)saa_wstruct(forwrefs) = globallineno;
  501.  
  502.         /*
  503.          * Hack to prevent phase error in the code
  504.          *   rol ax,x
  505.          *   x equ 1
  506.          *
  507.          * We rule that the presence of a forward reference
  508.          * cancels out the UNITY property of the number 1. This
  509.          * isn't _strictly_ necessary in pass one, since the
  510.          * problem occurs in pass two, but for the sake of
  511.          * having the passes as near to identical as we can
  512.          * manage, we do it like this.
  513.          */
  514.         if (output_ins.forw_ref) {
  515.         int i;
  516.         for (i=0; i<output_ins.operands; i++)
  517.             output_ins.oprs[i].type &= ~ONENESS;
  518.         }
  519.  
  520.         if (output_ins.opcode == I_EQU) {
  521.         /*
  522.          * Special `..' EQUs get processed in pass two,
  523.          * except `..@' macro-processor EQUs which are done
  524.          * in the normal place.
  525.          */
  526.         if (!output_ins.label)
  527.             report_error (ERR_NONFATAL,
  528.                   "EQU not preceded by label");
  529.         else if (output_ins.label[0] != '.' ||
  530.              output_ins.label[1] != '.' ||
  531.              output_ins.label[2] == '@') {
  532.             if (output_ins.operands == 1 &&
  533.             (output_ins.oprs[0].type & IMMEDIATE) &&
  534.             output_ins.oprs[0].wrt == NO_SEG) {
  535.             define_label (output_ins.label,
  536.                       output_ins.oprs[0].segment,
  537.                       output_ins.oprs[0].offset,
  538.                       ofmt, report_error);
  539.             } else if (output_ins.operands == 2 &&
  540.                    (output_ins.oprs[0].type & IMMEDIATE) &&
  541.                    (output_ins.oprs[0].type & COLON) &&
  542.                    output_ins.oprs[0].segment == NO_SEG &&
  543.                    output_ins.oprs[0].wrt == NO_SEG &&
  544.                    (output_ins.oprs[1].type & IMMEDIATE) &&
  545.                    output_ins.oprs[1].segment == NO_SEG &&
  546.                    output_ins.oprs[1].wrt == NO_SEG) {
  547.             define_label (output_ins.label,
  548.                       output_ins.oprs[0].offset | SEG_ABS,
  549.                       output_ins.oprs[1].offset,
  550.                       ofmt, report_error);
  551.             } else
  552.             report_error(ERR_NONFATAL, "bad syntax for EQU");
  553.         }
  554.         } else {
  555.         if (output_ins.label)
  556.             define_label (output_ins.label,
  557.                   current_seg, offs,
  558.                   ofmt, report_error);
  559.         offs += insn_size (current_seg, offs, sb,
  560.                    &output_ins, report_error);
  561.         set_curr_ofs (offs);
  562.         }
  563.         cleanup_insn (&output_ins);
  564.     }
  565.     nasm_free (line);
  566.     }
  567.     preproc->cleanup();
  568.  
  569.     if (terminate_after_phase) {
  570.     fclose(ofile);
  571.     remove(outname);
  572.     if (want_usage)
  573.         usage();
  574.     exit (1);
  575.     }
  576.  
  577.     /* pass two */
  578.     pass = 2;
  579.     saa_rewind (forwrefs);
  580.     if (*listname)
  581.     nasmlist.init(listname, report_error);
  582.     {
  583.     int *p = saa_rstruct (forwrefs);
  584.     if (p)
  585.         forwline = *p;
  586.     else
  587.         forwline = -1;
  588.     }
  589.     current_seg = ofmt->section(NULL, pass, &sb);
  590.     raa_free (offsets);
  591.     offsets = raa_init();
  592.     preproc->reset(fname, report_error, &nasmlist);
  593.     strcpy(currentfile,fname);
  594.     lineno = 0;
  595.     lineinc = 1;
  596.     globallineno = 0;
  597.     while ( (line = preproc->getline()) ) {
  598.     lineno += lineinc;
  599.     globallineno++;
  600.  
  601.     if (line[0] == '%') {
  602.         int ln, li;
  603.         char buf[FILENAME_MAX];
  604.  
  605.         /*
  606.          * This will be a line number directive. They come
  607.          * straight from the preprocessor, so we'll subject
  608.          * them to only minimal error checking.
  609.          */
  610.         if (!strncmp(line, "%line", 5) &&
  611.         sscanf(line, "%%line %d+%d %s", &ln, &li, buf) == 3) {
  612.         lineno = ln - li;
  613.         lineinc = li;
  614.         strncpy (currentfile, buf, FILENAME_MAX-1);
  615.         currentfile[FILENAME_MAX-1] = '\0';
  616.         }
  617.         continue;
  618.     }
  619.  
  620.     /* here we parse our directives; this is not handled by
  621.      * the 'real' parser. */
  622.  
  623.     if ( (i = getkw (line, &value)) ) {
  624.         switch (i) {
  625.           case 1:           /* [SEGMENT n] */
  626.         seg = ofmt->section (value, pass, &sb);
  627.         if (seg == NO_SEG) {
  628.             report_error (ERR_PANIC,
  629.                   "invalid segment name on pass two");
  630.         } else
  631.             current_seg = seg;
  632.         break;
  633.           case 2:           /* [EXTERN label] */
  634.         break;
  635.           case 3:           /* [BITS bits] */
  636.         switch (atoi(value)) {
  637.           case 16:
  638.           case 32:
  639.             sb = atoi(value);
  640.             break;
  641.           default:
  642.             report_error(ERR_PANIC,
  643.                  "invalid [BITS] value on pass two",
  644.                  value);
  645.             break;
  646.         }
  647.         break;
  648.           case 4:               /* [GLOBAL symbol] */
  649.         break;
  650.           case 5:               /* [COMMON symbol size] */
  651.         break;
  652.           case 6:               /* [ABSOLUTE addr] */
  653.         current_seg = NO_SEG;
  654.         abs_offset = readnum(value, &rn_error);
  655.         if (rn_error)
  656.             report_error (ERR_PANIC, "invalid ABSOLUTE address "
  657.                   "in pass two");
  658.         break;
  659.           default:
  660.         if (!ofmt->directive (line+1, value, 2))
  661.             report_error (ERR_PANIC, "invalid directive on pass two");
  662.         break;
  663.         }
  664.     } else {
  665.         long offs = get_curr_ofs;
  666.         parse_line (current_seg, offs, lookup_label, 2,
  667.             line, &output_ins, ofmt, report_error);
  668.         if (globallineno == forwline) {
  669.         int *p = saa_rstruct (forwrefs);
  670.         if (p)
  671.             forwline = *p;
  672.         else
  673.             forwline = -1;
  674.         output_ins.forw_ref = TRUE;
  675.         } else
  676.         output_ins.forw_ref = FALSE;
  677.  
  678.         /*
  679.          * Hack to prevent phase error in the code
  680.          *   rol ax,x
  681.          *   x equ 1
  682.          */
  683.         if (output_ins.forw_ref) {
  684.         int i;
  685.         for (i=0; i<output_ins.operands; i++)
  686.             output_ins.oprs[i].type &= ~ONENESS;
  687.         }
  688.  
  689.         obuf = line;
  690.         if (output_ins.label)
  691.         define_label_stub (output_ins.label, report_error);
  692.         if (output_ins.opcode == I_EQU) {
  693.         /*
  694.          * Special `..' EQUs get processed here, except
  695.          * `..@' macro processor EQUs which are done above.
  696.          */
  697.         if (output_ins.label[0] == '.' &&
  698.             output_ins.label[1] == '.' &&
  699.             output_ins.label[2] != '@') {
  700.             if (output_ins.operands == 1 &&
  701.             (output_ins.oprs[0].type & IMMEDIATE)) {
  702.             define_label (output_ins.label,
  703.                       output_ins.oprs[0].segment,
  704.                       output_ins.oprs[0].offset,
  705.                       ofmt, report_error);
  706.             } else if (output_ins.operands == 2 &&
  707.                    (output_ins.oprs[0].type & IMMEDIATE) &&
  708.                    (output_ins.oprs[0].type & COLON) &&
  709.                    output_ins.oprs[0].segment == NO_SEG &&
  710.                    (output_ins.oprs[1].type & IMMEDIATE) &&
  711.                    output_ins.oprs[1].segment == NO_SEG) {
  712.             define_label (output_ins.label,
  713.                       output_ins.oprs[0].offset | SEG_ABS,
  714.                       output_ins.oprs[1].offset,
  715.                       ofmt, report_error);
  716.             } else
  717.             report_error(ERR_NONFATAL, "bad syntax for EQU");
  718.         }
  719.         }
  720.         offs += assemble (current_seg, offs, sb,
  721.                   &output_ins, ofmt, report_error, &nasmlist);
  722.         cleanup_insn (&output_ins);
  723.         set_curr_ofs (offs);
  724.     }
  725.     nasm_free (line);
  726.     }
  727.     preproc->cleanup();
  728.     nasmlist.cleanup();
  729. }
  730.  
  731. static int getkw (char *buf, char **value) {
  732.     char *p, *q;
  733.  
  734.     if (*buf!='[')
  735.         return 0;
  736.     p = buf;
  737.     while (*p && *p != ']') p++;
  738.     if (!*p)
  739.     return 0;
  740.     q = p++;
  741.     while (*p && *p != ';') {
  742.     if (!isspace(*p))
  743.         return 0;
  744.     p++;
  745.     }
  746.     q[1] = '\0';
  747.  
  748.     p = buf+1;
  749.     while (*buf && *buf!=' ' && *buf!=']' && *buf!='\t')
  750.         buf++;
  751.     if (*buf==']') {
  752.     *buf = '\0';
  753.     *value = buf;
  754.     } else {
  755.     *buf++ = '\0';
  756.         while (isspace(*buf)) buf++;   /* beppu - skip leading whitespace */
  757.     *value = buf;
  758.     while (*buf!=']') buf++;
  759.     *buf++ = '\0';
  760.     }
  761.     for (q=p; *q; q++)
  762.     *q = tolower(*q);
  763.     if (!strcmp(p, "segment") || !strcmp(p, "section"))
  764.         return 1;
  765.     if (!strcmp(p, "extern"))
  766.         return 2;
  767.     if (!strcmp(p, "bits"))
  768.         return 3;
  769.     if (!strcmp(p, "global"))
  770.         return 4;
  771.     if (!strcmp(p, "common"))
  772.         return 5;
  773.     if (!strcmp(p, "absolute"))
  774.         return 6;
  775.     return -1;
  776. }
  777.  
  778. static void report_error (int severity, char *fmt, ...) {
  779.     va_list ap;
  780.  
  781.     /*
  782.      * See if it's a suppressed warning.
  783.      */
  784.     if ((severity & ERR_MASK) == ERR_WARNING &&
  785.     (severity & ERR_WARN_MASK) != 0 &&
  786.     suppressed[ (severity & ERR_WARN_MASK) >> ERR_WARN_SHR ])
  787.     return;                   /* and bail out if so */
  788.  
  789.     if (severity & ERR_NOFILE)
  790.     fputs ("nasm: ", use_stdout ? stdout : stderr);
  791.     else
  792.     fprintf (use_stdout ? stdout : stderr, "%s:%d: ", currentfile,
  793.          lineno + (severity & ERR_OFFBY1 ? lineinc : 0));
  794.  
  795.     if ( (severity & ERR_MASK) == ERR_WARNING)
  796.     fputs ("warning: ", use_stdout ? stdout : stderr);
  797.     else if ( (severity & ERR_MASK) == ERR_PANIC)
  798.     fputs ("panic: ", use_stdout ? stdout : stderr);
  799.  
  800.     va_start (ap, fmt);
  801.     vfprintf (use_stdout ? stdout : stderr, fmt, ap);
  802.     fputc ('\n', use_stdout ? stdout : stderr);
  803.  
  804.     if (severity & ERR_USAGE)
  805.     want_usage = TRUE;
  806.  
  807.     switch (severity & ERR_MASK) {
  808.       case ERR_WARNING:
  809.     /* no further action, by definition */
  810.     break;
  811.       case ERR_NONFATAL:
  812.     terminate_after_phase = TRUE;
  813.     break;
  814.       case ERR_FATAL:
  815.     if (ofile) {
  816.         fclose(ofile);
  817.         remove(outname);
  818.     }
  819.     if (want_usage)
  820.         usage();
  821.     exit(1);               /* instantly die */
  822.     break;                   /* placate silly compilers */
  823.       case ERR_PANIC:
  824.     abort();               /* halt, catch fire, and dump core */
  825.     break;
  826.     }
  827. }
  828.  
  829. static void usage(void) {
  830.     fputs("type `nasm -h' for help\n", use_stdout ? stdout : stderr);
  831. }
  832.  
  833. static void register_output_formats(void) {
  834.     /* Flat-form binary format */
  835. #ifdef OF_BIN
  836.     extern struct ofmt of_bin;
  837. #endif
  838.     /* Unix formats: a.out, COFF, ELF */
  839. #ifdef OF_AOUT
  840.     extern struct ofmt of_aout;
  841. #endif
  842. #ifdef OF_COFF
  843.     extern struct ofmt of_coff;
  844. #endif
  845. #ifdef OF_ELF
  846.     extern struct ofmt of_elf;
  847. #endif
  848.     /* Linux strange format: as86 */
  849. #ifdef OF_AS86
  850.     extern struct ofmt of_as86;
  851. #endif
  852.     /* DOS and DOS-ish formats: OBJ, OS/2, Win32 */
  853. #ifdef OF_OBJ
  854.     extern struct ofmt of_obj;
  855. #endif
  856. #ifdef OF_WIN32
  857.     extern struct ofmt of_win32;
  858. #endif
  859. #ifdef OF_OS2
  860.     extern struct ofmt of_os2;
  861. #endif
  862. #ifdef OF_RDF
  863.     extern struct ofmt of_rdf;
  864. #endif
  865. #ifdef OF_DBG     /* debug format must be included specifically */
  866.     extern struct ofmt of_dbg;
  867. #endif
  868.  
  869. #ifdef OF_BIN
  870.     ofmt_register (&of_bin);
  871. #endif
  872. #ifdef OF_AOUT
  873.     ofmt_register (&of_aout);
  874. #endif
  875. #ifdef OF_COFF
  876.     ofmt_register (&of_coff);
  877. #endif
  878. #ifdef OF_ELF
  879.     ofmt_register (&of_elf);
  880. #endif
  881. #ifdef OF_AS86
  882.     ofmt_register (&of_as86);
  883. #endif
  884. #ifdef OF_OBJ
  885.     ofmt_register (&of_obj);
  886. #endif
  887. #ifdef OF_WIN32
  888.     ofmt_register (&of_win32);
  889. #endif
  890. #ifdef OF_OS2
  891.     ofmt_register (&of_os2);
  892. #endif
  893. #ifdef OF_RDF
  894.     ofmt_register (&of_rdf);
  895. #endif
  896. #ifdef OF_DBG
  897.     ofmt_register (&of_dbg);
  898. #endif
  899.     /*
  900.      * set the default format
  901.      */
  902.     ofmt = &OF_DEFAULT;
  903. }
  904.  
  905. #define BUF_DELTA 512
  906.  
  907. static FILE *no_pp_fp;
  908. static efunc no_pp_err;
  909.  
  910. static void no_pp_reset (char *file, efunc error, ListGen *listgen) {
  911.     no_pp_err = error;
  912.     no_pp_fp = fopen(file, "r");
  913.     if (!no_pp_fp)
  914.     no_pp_err (ERR_FATAL | ERR_NOFILE,
  915.            "unable to open input file `%s'", file);
  916.     (void) listgen;               /* placate compilers */
  917. }
  918.  
  919. static char *no_pp_getline (void) {
  920.     char *buffer, *p, *q;
  921.     int bufsize;
  922.  
  923.     bufsize = BUF_DELTA;
  924.     buffer = nasm_malloc(BUF_DELTA);
  925.     p = buffer;
  926.     while (1) {
  927.     q = fgets(p, bufsize-(p-buffer), no_pp_fp);
  928.     if (!q)
  929.         break;
  930.     p += strlen(p);
  931.     if (p > buffer && p[-1] == '\n')
  932.         break;
  933.     if (p-buffer > bufsize-10) {
  934.         bufsize += BUF_DELTA;
  935.         buffer = nasm_realloc(buffer, bufsize);
  936.     }
  937.     }
  938.  
  939.     if (!q && p == buffer) {
  940.     nasm_free (buffer);
  941.     return NULL;
  942.     }
  943.  
  944.     /*
  945.      * Play safe: remove CRs as well as LFs, if any of either are
  946.      * present at the end of the line.
  947.      */
  948.     while (p > buffer && (p[-1] == '\n' || p[-1] == '\r'))
  949.     *--p = '\0';
  950.  
  951.     /*
  952.      * Handle spurious ^Z, which may be inserted into source files
  953.      * by some file transfer utilities.
  954.      */
  955.     buffer[strcspn(buffer, "\032")] = '\0';
  956.  
  957.     return buffer;
  958. }
  959.  
  960. static void no_pp_cleanup (void) {
  961.     fclose(no_pp_fp);
  962. }
  963.